﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using EntreeServer.Module;
using EntreeServer.Module.ActionTray;
using EntreeServer.Module.Configuration;
using EntreeServer.Module.Controls;
using Microsoft.SharePoint;

namespace ME.SDK.SampleApplication
{
    [Guid("425f944b-91d2-4ad9-8194-0c4c9a022149")]
    public class ListSearchApp : EntreeApplication
    {

        public override string PluginPath
        {
            get
            {
                return "/_layouts/images/ME.SDK.SampleApplication/ME SDK Sample Application";
            }
        }
        public override string Title
        {
            get { return "List Search App"; }
        }

        public override void QueryList(EntreeScopeObject EntreeScope, EntreeListObject output)
        {
            if (EntreeScope.Properties.Contains("Type", "LoadApplication") || EntreeScope.Properties.Contains("Type", "ReloadApplication"))
            {
                //get the list and view using values from the config
                var list = SPContext.Current.Web.Lists[this.Config.ListId];
                var view = list.Views[this.Config.ViewId];

                //render search screen
                output.ListTitle = "Search {0}".FormatString(list.Title);

                //add search form controls
                var searchForm = output.AddListGroup<EntreeButtonGroup>();
                var searchBox = searchForm.AddFormItem<EntreeTextBox>("SearchQuery");
                searchBox.Name = "Search";
                var searchButton = searchForm.AddListItem<EntreeListItemTitleIcon>();
                searchButton.Title = "Search";
                searchButton.Icon = "{0}/ico-search-16.png".FormatString(this.PluginPath);

                //add group for results
                var resultsGroup = output.AddListGroup();

                //set ClickAction targeting the results group
                searchButton.ClickAction = new EntreeActiveUpdateObject(this)
                {
                    UpdateTarget = resultsGroup,
                    UpdateType = EntreeActiveUpdateObject.EntreeActiveUpdateType.Replace,
                    FormSubmit = true,
                    OverridePanelTargetSelf = true
                };

                if (this.ViewState.ContainsKey("SearchQuery") && !string.IsNullOrEmpty(this.ViewState["SearchQuery"].ToString()))
                {
                    searchBox.Value = this.ViewState["SearchQuery"].ToString();
                    //render search results using saved query info
                    var itemId = 0;
                    if (this.ViewState.ContainsKey(EntreeServer.Module.BasicPluginActions.ScopeProperties.SPListItemID)) itemId = Convert.ToInt32(this.ViewState[EntreeServer.Module.BasicPluginActions.ScopeProperties.SPListItemID]);
                    renderResults(resultsGroup, this.ViewState["SearchQuery"].ToString(), itemId, output.PanelCount > 1);
                }

                //set action scope properties
                setActionScopeProperties(output.ActionScope, EntreeServer.Module.BasicPluginActions.ScopeTypes.SPView, 0);
            }
            else if (EntreeScope.Properties.Contains("Type", "RenderItemDetails"))
            {

                //get the list, view and item using values from the config
                var list = SPContext.Current.Web.Lists[this.Config.ListId];
                var view = list.Views[this.Config.ViewId];
                SPListItem item = null;
                try
                {
                    item = list.GetItemById(int.Parse(EntreeScope.Properties[EntreeServer.Module.BasicPluginActions.ScopeProperties.SPListItemID]));
                }
                catch (ArgumentException)
                {
                    item = null;
                }

                if (item == null)
                {
                    //item was deleted
                    if (output.PanelCount < 2)
                    {
                        //render search screen
                        EntreeScope.Properties["Type"] = "ReloadApplication";
                        QueryList(EntreeScope, output);
                    }
                    return;
                }

                //store current item id in view state
                this.ViewState[EntreeServer.Module.BasicPluginActions.ScopeProperties.SPListItemID] = item.ID;

                //render item details
                var group = output.AddListGroup();
                foreach (string viewField in view.ViewFields)
                {
                    var field = list.Fields.GetFieldByInternalName(viewField);
                    if (field.Hidden) continue;
                    var li = group.AddListItem<EntreeListItemDetailNameValue>();
                    li.Name = field.Title;
                    li.Value = field.GetFieldValueAsText(item[field.Id]);
                }

                //add back button for single panel
                if (output.PanelCount < 2)
                {
                    var backAction = new ActionItem(string.Empty, "ListSearchApp.Back")
                    {
                        Title = "Back",
                        ClickAction = new EntreeClickActionObject(this)
                        {
                            AnimationStyle = AnimationStyles.SLIDE_RIGHT
                        }
                    };
                    backAction.ClickAction.Properties["Type"] = "ReloadApplication";
                    output.HomeBar.ActionItems.Items.Add(backAction);
                }

                //set action scope properties to get ootb action(s)
                setActionScopeProperties(output.ActionScope, EntreeServer.Module.BasicPluginActions.ScopeTypes.SPListItem_Details, item.ID);
            }
        }

        public override void ActiveUpdate(EntreeScopeObject scope, EntreeListItemCollection output)
        {
            //get query text
            var searchQuery = scope.FormProperties["SearchQuery"];
            //store query in view state
            this.ViewState["SearchQuery"] = searchQuery;
            //remove current selected item
            this.ViewState.Remove(EntreeServer.Module.BasicPluginActions.ScopeProperties.SPListItemID);

            //render results using current search query
            renderResults(output, searchQuery, 0, output.PanelCount > 1);
        }

        public override bool BuildPanelsByScope(EntreeScopeObject currentScope, EntreeScopeCollection panelScopes, PanelDirection direction)
        {
            return base.BuildPanelsByScope(currentScope, panelScopes, direction);
        }

        public override EntreeServer.Module.Configuration.EntreeConfigPartCollection CreateConfigParts()
        {
            //create and return the custom configpart
            return new EntreeConfigPartCollection
            {
                new ListSearchAppConfigPart(this)
            };
        }

        #region public properties
        /// <summary>
        /// Property to hold Config class. Public properties are propagated to the SP database on config save
        /// </summary>
        public ListSearchAppConfig Config { get; set; }
        #endregion

        #region generate caml query
        private SPQuery generateQuery(string queryText)
        {
            //get the list and view using values from the config
            var list = SPContext.Current.Web.Lists[this.Config.ListId];
            var view = list.Views[this.Config.ViewId];

            var sb = new StringBuilder();

            if (this.Config.FieldInternalNames.Count == 1)
            {
                //generate single value query
                sb.AppendFormat(@"<Where><Contains><FieldRef Name=""{0}"" /><Value Type=""Text"">{1}</Value></Contains></Where>", this.Config.FieldInternalNames.First(), queryText);
            }
            else if (this.Config.FieldInternalNames.Count == 2)
            {
                //generate two value query
                sb.AppendFormat(@"<Where><Or><Contains><FieldRef Name=""{0}"" /><Value Type=""Text"">{1}</Value></Contains><Contains><FieldRef Name=""{2}"" /><Value Type=""Text"">{1}</Value></Contains></Or></Where>", this.Config.FieldInternalNames.First(), queryText, this.Config.FieldInternalNames.Last());
            }
            else
            {
                //generate query for more than two fields
                sb.Append("<Or>");

                sb.AppendFormat(@"<Contains><FieldRef Name=""{0}"" /><Value Type=""Text"">{1}</Value></Contains><Contains><FieldRef Name=""{2}"" /><Value Type=""Text"">{1}</Value></Contains>", this.Config.FieldInternalNames.First(), queryText, this.Config.FieldInternalNames.Last());

                for (int i = 2; i < this.Config.FieldInternalNames.Count; i++)
                {
                    sb.Insert(0, "<Or>");
                    sb.AppendFormat(@"<Contains><FieldRef Name=""{0}"" /><Value Type=""Text"">{1}</Value></Contains>", this.Config.FieldInternalNames[i], queryText);
                    sb.Append("</Or>");
                }

                sb.Insert(0, "<Where>");
                sb.Append("</Where>");
            }

            return new SPQuery(view)
            {
                Query = sb.ToString()
            };
        }
        #endregion
        #region render results
        private void renderResults(IEntreeListItemContainer container, string searchQuery, int selectedItemId, bool selectItem)
        {
            //get the list and view using values from the config
            var list = SPContext.Current.Web.Lists[this.Config.ListId];
            var view = list.Views[this.Config.ViewId];

            //perform query on list
            var results = list.GetItems(generateQuery(searchQuery));

            //render results
            foreach (SPListItem item in results)
            {
                var li = container.AddListItem<EntreeListItemTitle>();
                li.Title = item.Title;
                //set selected item if it exists
                if (item.ID == selectedItemId && selectItem) li["Selected"] = true.ToString().ToLower();
                li.ClickAction = new EntreeClickActionObject(this);
                li.ClickAction.Properties[EntreeServer.Module.BasicPluginActions.ScopeProperties.SPListItemID] = item.ID.ToString();
                li.ClickAction.Properties["Type"] = "RenderItemDetails";
            }
        }
        #endregion
        #region action scope
        private void setActionScopeProperties(ActionScopeObject scope, string scopeType, int spListItemId)
        {
            //set ScopeType and appropriate properties to enable CRUD actions
            scope.ScopeType = scopeType;
            scope.Properties[EntreeServer.Module.BasicPluginActions.ScopeProperties.SPSiteUrl] = SPContext.Current.Site.Url;
            scope.Properties[EntreeServer.Module.BasicPluginActions.ScopeProperties.SPWebUrl] = SPContext.Current.Web.Url;
            scope.Properties[EntreeServer.Module.BasicPluginActions.ScopeProperties.SPListID] = this.Config.ListId.ToString();
            scope.Properties[EntreeServer.Module.BasicPluginActions.ScopeProperties.SPViewID] = this.Config.ViewId.ToString();
            if (spListItemId > 0) scope.Properties[EntreeServer.Module.BasicPluginActions.ScopeProperties.SPListItemID] = spListItemId.ToString();
        }
        #endregion
    }
}
